/*----------------------------------------------------------------
 * \file        ct_voip_losg_checker_mgr.h
 * \author      lilian lilian@hujiang.com
 * \date        2014/08/11
 * \brief
 *      the manager of VOIP lost packet checker.
 *----------------------------------------------------------------*/
#ifndef CTVOIP_LOST_CHECKER_MGR_H_
#define CTVOIP_LOST_CHECKER_MGR_H_

#include "command.h"
#include "ctTime.h"
#include <map>
#include <list>

class ctVOIPLostChecker;

class ctResendWaiter {
        public:
                enum eWaitRes {
                        eResendOkay = 0,
                        eResendAgain,
                        eResendTimeout,
                        eResendNone,
                };

                ctResendWaiter(ctVOIPLostChecker &checker, uint32_t seq);
                uint32_t seq() const { return seq_; }
                eWaitRes onPacket(uint32_t seq, const ctRTime& curtime);

        private:
                ctVOIPLostChecker&      checker_;
                const uint32_t          seq_;
                ctRTime                 life_time_;
                ctRTime                 last_req_resend_time_;
};

class ctVOIPLostChecker {
        public:
                ctVOIPLostChecker(uint32_t resend_timeout);
                ~ctVOIPLostChecker();

                void    setRTT(uint32_t rtt);
                int     checkLost(uint32_t seq, std::list<uint32_t> *need_resend_list, bool* i_am_resent=NULL);

                uint32_t resendIntervalMs() const {
                        return (rtt_*3)>>1;
                }
                uint32_t resendTimeoutMs() const {
                        return resend_timeout_ms_;
                }
                bool    checkTimeout(const ctRTime& curtime) const {
                        return (last_time_.elapse(curtime) > CHECKER_TIMEOUT_MS);
                }

        private:
                void checkResendWaiter(uint32_t seq, std::list<uint32_t>* need_resend_list, bool* i_am_resent);

        public:
                static const int MAX_RESEND_COUNT_ONCE = 3;
                static const uint32_t CHECKER_TIMEOUT_MS = 60*1000;
                static const uint32_t RTT_DEF_MS = 100;
                static const uint32_t RTT_MIN_MS = 60;
                static const uint32_t RTT_MAX_MS = 500;

        private:
                typedef std::list<ctResendWaiter*> WaiterList;
                uint32_t        resend_timeout_ms_;
                uint32_t        rtt_;
                uint32_t        max_seq_;
                WaiterList      waiter_list_;
                ctRTime         last_time_;
};

class ctVOIPLostCheckerMgr {
        public:
                ctVOIPLostCheckerMgr(uint32_t resend_timeout=400);
                ~ctVOIPLostCheckerMgr();

        public:
                int     checkLost(uint32_t uid, uint32_t seq, std::list<uint32_t> *need_resend_list, bool* i_am_resent=NULL);
                void    checkTimeout();

        private:
                //<userid, ctVOIPLostChecker>
                typedef std::map<uint32_t, ctVOIPLostChecker*> CheckerMap;
        private:
                uint32_t        resend_timeout_ms_;
                CheckerMap      checker_map_;
};

#endif //CTVOIP_LOST_CHECKER_MGR_H_
